package cn.ly.core.thread;

public class ProducerConsummer {
	
	public static void main(String[] args) {
		MyStack ms = new MyStack();
		Thread p = new Producer(ms);
		Thread c1 = new Consummer(ms);
		Thread c2 = new Consummer(ms);
		/**
		 * 由于开启了两个消费者线程，当生产者线程放入26个字母结束线程执行后，两个消费者线程
		 * 还回调用pop方法，然后调用了this.wait()，当前线程进入了stack的锁池中，但是生产者
		 * 线程已经退出了，没有线程再唤醒生产者线程了，所以程序一致存活着...,红灯亮着...
		 */
		//Thread c3 = new Consummer(ms);
		p.start();
		c1.start();
		c2.start();
		//c3.start();
	}
	
}

class MyStack{
	char[] data = new char[10];
	int index = 0;                    //用index做为计数器，当计数器等数组长度时，让当前的生产者线程停下来，this.wait()进入阻塞队列
	public synchronized void push(char c){
		while(index == data.length){  //之所以用循环方式，是因为可能没有消费者来消费，或者在消费期间，index还没有改变
			try{                      //如果是多个producer有可能是某一个producer把其它的producer和consummer唤醒的
				this.wait();          //让当前生产者线程进入等待队列，不要再向stack中放数据
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		data[index] = c;
		index++;
		System.out.println(c + " is pushed:");
		this.notifyAll();
		print();
	}
	
	public synchronized void pop(){
		while(index == 0){            //之所以用循环方式，是因为可能没有生产者线程向stack中放入数据，或者在生成期间，index还没有改变
			try{
				this.wait();          //让当前消费线程进入等待队列，不要再向stack取数据
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		index--;
		System.out.println(data[index] + " is poped:");
		data[index] = ' ';
		this.notifyAll();
		print();
	}
	private void print(){
		for(int i = 0; i < this.data.length; i++){
			System.out.print(data[i] + "\t");
		}
		System.out.println();
	}
}

class Producer extends Thread{
	MyStack ms;
	public Producer(MyStack ms){
		this.ms = ms;
	}
	public void run(){
		for(char c = 'A'; c <= 'Z'; c++){
			ms.push(c);
			try{
				Thread.sleep(10);
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		System.out.println("---last Producer---");
	}
	
}

class Consummer extends Thread{
	MyStack ms;
	public Consummer(MyStack ms){
		this.ms = ms;
	}
	public void run(){
		for(int i = 0; i < 26; i++){
			ms.pop();
			try{
				Thread.sleep(10);
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		System.out.println("---last Consummer---");
	}
	
}
